package com.siss.tenancy.user.config;


import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.github.pagehelper.PageHelper;
import io.seata.rm.datasource.DataSourceProxy;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Properties;

/**
 * mybatis 配置数据源类
 *
 * @author ygw
 * @date 2017年7月11日
 * @since 1.8
 */
@Configuration
public class MybatisConfiguration implements EnvironmentAware {


    private Environment environment;

    @Bean
    public Myproperties myproperties() {
        // 现在的code:
        Iterable sources = ConfigurationPropertySources.get(environment);
        Binder binder = new Binder(sources);
        BindResult bindResult = binder.bind("spring.datasource", Myproperties.class);
        Myproperties properties = (Myproperties) bindResult.get();
        return properties;
    }

    @Bean
    public DataSource druidDataSource(Myproperties myproperties) {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(myproperties.getUrl());
        druidDataSource.setUsername(myproperties.getUserName());
        druidDataSource.setPassword(myproperties.getPassword());
        druidDataSource.setDriverClassName(StringUtils.isNotBlank(myproperties.getDriverClassName()) ? myproperties.getDriverClassName() : "com.mysql.jdbc.Driver");
        druidDataSource.setMaxActive(StringUtils.isNotBlank(myproperties.getMaxActive()) ? Integer.parseInt(myproperties.getMaxActive()) : 10);
        druidDataSource.setInitialSize(StringUtils.isNotBlank(myproperties.getInitialSize()) ? Integer.parseInt(myproperties.getInitialSize()) : 1);
        druidDataSource.setMaxWait(StringUtils.isNotBlank(myproperties.getMaxWait()) ? Integer.parseInt(myproperties.getMaxWait()) : 60000);
        druidDataSource.setMinIdle(StringUtils.isNotBlank(myproperties.getMinIdle()) ? Integer.parseInt(myproperties.getMinIdle()) : 3);
        druidDataSource.setTimeBetweenEvictionRunsMillis(StringUtils.isNotBlank(myproperties.getTimeBetweenEvictionRunsMillis()) ?
                Integer.parseInt(myproperties.getTimeBetweenEvictionRunsMillis()) : 60000);
        druidDataSource.setMinEvictableIdleTimeMillis(StringUtils.isNotBlank(myproperties.getMinEvictableIdleTimeMillis()) ?
                Integer.parseInt(myproperties.getMinEvictableIdleTimeMillis()) : 300000);
        druidDataSource.setValidationQuery(StringUtils.isNotBlank(myproperties.getValidationQuery()) ? myproperties.getValidationQuery() : "select 'x'");
        druidDataSource.setTestWhileIdle(StringUtils.isNotBlank(myproperties.getTestWhileIdle()) ? Boolean.parseBoolean(myproperties.getTestWhileIdle()) : true);
        druidDataSource.setTestOnBorrow(StringUtils.isNotBlank(myproperties.getTestOnBorrow()) ? Boolean.parseBoolean(myproperties.getTestOnBorrow()) : false);
        druidDataSource.setTestOnReturn(StringUtils.isNotBlank(myproperties.getTestOnReturn()) ? Boolean.parseBoolean(myproperties.getTestOnReturn()) : false);
        druidDataSource.setPoolPreparedStatements(StringUtils.isNotBlank(myproperties.getPoolPreparedStatements()) ? Boolean.parseBoolean(myproperties.getPoolPreparedStatements()) : true);
        druidDataSource.setMaxOpenPreparedStatements(StringUtils.isNotBlank(myproperties.getMaxOpenPreparedStatements()) ? Integer.parseInt(myproperties.getMaxOpenPreparedStatements()) : 20);
        druidDataSource.setLogAbandoned(StringUtils.isNotBlank(myproperties.getLogAbandoned()) ? Boolean.parseBoolean(myproperties.getLogAbandoned()) : true);
        druidDataSource.setRemoveAbandoned(StringUtils.isNotBlank(myproperties.getRemoveAbandoned()) ? Boolean.parseBoolean(myproperties.getRemoveAbandoned()) : true);
        druidDataSource.setRemoveAbandonedTimeout(StringUtils.isNotBlank(myproperties.getRemoveAbandonedTimeout()) ?
                Integer.parseInt(myproperties.getRemoveAbandonedTimeout()) : 60000);
        try {
            druidDataSource.setFilters(StringUtils.isNotBlank(myproperties.getFilters()) ? myproperties.getFilters() : "stat, wall");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return druidDataSource;
    }

    //必须要加的，seata是通过代理数据源实现的分布式事务
    @Bean
    public DataSourceProxy dataSourceProxy(DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSource, Myproperties myproperties) {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        if (StringUtils.isNotBlank(myproperties.getTypeAliasesPackage())) {
            bean.setTypeAliasesPackage(myproperties.getTypeAliasesPackage());
        }
        //分页插件
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);
        //添加XML目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

        Interceptor[] plugins = new Interceptor[]{pageHelper};
        bean.setPlugins(plugins);
        try {
            bean.setMapperLocations(resolver.getResources(myproperties.getXmlLocation()));
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    /**
     * 注册一个druid StatViewServlet
     *
     * @return
     */
    @Bean
    public ServletRegistrationBean druidStatViewServlet() {
        //org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        //添加初始化参数：initParams
        //IP白名单(没有配置或者为空，则允许所有访问)
        servletRegistrationBean.addInitParameter("allow", "");
        //IP黑名单 (存在共同时，deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
        servletRegistrationBean.addInitParameter("deny", "");
        //登录查看信息的账号密码.
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "123456");
        //是否能够重置数据. 禁用HTML页面上的“Reset All”功能
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        return servletRegistrationBean;

    }

    /**
     * 注册一个：druid filterRegistrationBean
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean druidStatFilter() {

        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());

        //添加过滤规则.
        filterRegistrationBean.addUrlPatterns("/*");

        //添加不需要忽略的格式信息.
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }


    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
